Vol 1 Number 4 In the fourth issue of WINDOID, we address more of the many questions and problems people have sent in. Quite a number of people have expressed interest in moving a group of buttons or fields on a card. Sioux Lacy, one of our outstanding HyperCard testers, has given us a way to group buttons and/or fields and move them, in a group, within a card and even onto other cards. Sioux has also written for us an article on Finding multi-word strings in blocks of text. This is one that everyone has asked for. Phil Wyman, with assistance from Steve All, two more great HyperCard testers, have given us further HyperCard user tips. We really appreciate all of the cards people have sent us with the tips they have found. In this way we can pass on useful tips to many hundreds of HyperCard users. Paul Foraker, our newest tester, has submitted an AutoLink script. Using this great little shortcut for scripting buttons gives you another productivity tip I am sure you will find interesting. Steve Maller has done it again! ResCopy is his latest XCMD effort to give us a safe, elegant, and easy way to move resources around in HyperCard. This version is his ÒshippingÓ version and does not have a time bomb in it. You are free to give it away to your HyperCarding friends. This is one stack that people who do not have it will lust for. Sioux Lacy has given us Groupies 1.3, featured in this issue of WINDOID. This is a must stack for serious HyperCard users. I really appreciate SiouxÕs efforts in bringing us all of these great articles and I am equally sure that you will also. These two stack are on the Apple HyperCard User Group file server and can be obtained only here in Cupertino. If your favorite bulletin board does not have them, please ask them to have someone upload them. ========== AutoLink by Paul Foraker Shortly after you get HyperCard installed on your hard disk, you may notice that you are collecting a large number of other peopleÕs stacks. One way of keeping track of all of them is to stuff them into a folder and put a button for them on a card in your Home stack. Since the original Home card already comes with 19 buttons (and room for about 24), you might want to make another card for holding buttons that take you to your miscellaneous stacks. To avoid having to name and link all the buttons on a new card to the stacks IÕve collected, I wrote a variation on Danny GoodmanÕs script which takes you to a stack even though the button has no script or link. In this version, a button named Ònew buttonÓ opens the familiar Standard File dialog and then gets the name of whatever stack you select, changes the name of itself (the button) to the selected stack, then goes there. If the button already has a name (other than Ònew buttonÓ), the script simply goes to the stack. This eliminates the necessity for linking or scripting multiple buttons on a card. To start from scratch from your Home card, select New Card (CMD-N) and title the new card ÒBackYardÓ (or anything else fun). Type the script below into the script window for the card. (You can skip over typing the comments if you wish.) Then make a new button (you can select an icon for it Ñ I use the generic stack icon). Now hold down the Option key and drag copies of the Ònew buttonÓ around onto your card. (You can use the Shift key to constrain the movement so theyÕre lined up neatly.) Next, select the Browse tool again and click on one of your new buttons. YouÕll get Standard File asking you Òwhere is the stack you want?Ó Double click on one of the stacks in the list, the new button will get a name change, and youÕll be off to the new stack. From there, you can hit the escape (~) key to go right back to the BackYard to AutoLink another button. --AutoLink script --variation on Danny GoodmanÕs script --by Paul Foraker on mouseUp put the short name of this stack  into thisStack --saving the name for --use later get the short name of the target --puts the ÔshortÕ name of the --button you clicked on into ÔitÕ if it is Ònew buttonÓ then --Oh boy... a new stack has arrived! push card --saves the BackYard card id --so we can come back to it set lockMessages to true --stops any other scripts from running set lockScreen to true --freezes the screen so weÕre not ÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊ --distracted by fast moving cards. go stack Òthe stack you want?Ó --since there is no stack by that --name, HyperCard will respond by --asking you where it is. --Standard File will open and you --can select a stack --or click on Cancel. get the short name of this stack --here weÕre asking for the --short name of the ÔnewÕ stack if it is thisStack then --checking for clicking on the Cancel button pop card --go back to our BackYard card set lockScreen to false --unlocking the screen display exit mouseUp --pretend it never happened end if --end of checking for ÔcancelÕ put it into stackName --putting short name of the stack into --ÕstackNameÕ pop card --go back to our BackYard card set the name of the target to stackName --rename the button set showName of the target to true --we want to see the name set the script of the target to empty --make sure thereÕs no script in --the button set lockScreen to false --unlocking the screen display set lockMessages to false --now messages can fly around again. end if --marks the end of the loop --for a Ônew button.Õ --now, we make sure you didnÕt click on the card or background: if the short name of target is the short name of this card then exit mouseUp if the short name of target is the short name of this bkgnd then exit mouseUp visual iris open to black --just for fun go STACK it --ÔitÕ will be either the new stack or Ñone thatÕs already been identified end mouseUp ========== HyperCard Hints by Phil Wyman 1. There are some interesting properties in HyperTalk that you may not know about: a. is a global property which tells you which version of HyperCard you are currently using. This property will become very useful after new versions are released. Since the new versions will have added features that old versions do not understand, stack developers will want to check to see if their stack is currently running on a version of HyperCard that supports those new features. b. is another global property. It will tell you that the name of the program is HyperCard. I have not found a way to use this yet, so if anyone has any ideas, let me know. c. is a global property which will tell you how many bytes you have left on the drive that the current stack is located on. 2. You can send a message up the heirarchy manually by using the message box. For instance, if you want an OPENSTACK message sent without having to reopen your stack, just type OPENSTACK into the message box and hit return or enter. Any handler, starting with any handler in the current card, which uses OPENSTACK, will receive that message. Some users are having trouble sending their own messages. In a script, you can just type the name of your message on a line by itself and that message will be sent. If HyperCard does not find a handler with that message, it will throw up a dialog telling you it canÕt understand . You can also send a message with the command. You can have difficulty with the command if you are trying to send across stacks. Try going to the stack first before using . For example: send mouseup to button 1 of card 1 of stack "Home" will generate a HyperCard error "expected end of line after send". To get the "mouseup" message to the button, try this: go to card 1 of stack "Home" send mouseup to button 1 3. When you are printing your script from the script editor, you do not have to print the whole script. If you want to just print a portion of your script, then select the part you want, then click on the print button. Only your selected text will print. 4. The Tab key moves you between fields on a card in the order of their field number (which can be changed with Bring Closer and Send Farther). But a useful fact for data entry is that Shift-Tab navigates you through fields in reverse order. 5. Choosing a selection with the Selection tool can leave you with a lot of extra white space surrounding your selection. And you may already know that Command-S shrinks a selection rectangle until there is no surrounding white space. What if you want a rectangular selection but no extra white space? Hold down the Command key before selecting with the Selection tool and just that will happen. 6. If you are writing commercial stacks and need to restrict the user-level, you may wish to tell users in your About Box that they can access ÒFull MenusÓ by holding down the Command key before clicking the menu. 7. So you think that those tiny pictures in ÒRecentÓ are neat? You can create them yourself. Copy a card and hold down the Shift key when pasting it back in. YouÕll get an image of the card in miniature (but no actions from buttons or fields to type into). There are three ways in which the script writer can inquire about the presence of a string in a block of text: FIND, CONTAINS and OFFSET. These can be used separately or in combination. The FIND command will highlight the next occurence of the first word of the string if all words in the string are somewhere on the card. Another option is to test if a particular container (field or variable) CONTAINS the string. This test will determine an exact match on the entire string. The function OFFSET will return the character in the container on which the match begins. This can also be used to test IF the field/variable includes the string, since if it does NOT, offset will return 0. Depending on the context of the search, the script writer may opt for one or a combination of these. If the scope of the search is small, and across known fields, CONTAINS or OFFSET can be used. However, if the search is across many fields in a large stack, FIND is a good mechanism to narrow down the number of fields that have to be examined to see if they CONTAIN the string. To FIND a multi-word string For example, you would like to find an exact match for the string ÒHello thereÓ. You will discover that HyperCard is generous in its find criteria, and also matches the following: ÒHello world. Is there life out there?Ó This can be problematic if the search is taking place inside a handler, rather than at the control of a human who can continue to hit the return key. The way to circumvent this is to do your match in 2 steps. Supposing you expect the match to be in a background field, try calling a function (until youÕve searched the entire stack) that does this: function multiWordFind string repeat with x = 1 to the number of bkgnd fields if field x contains string then return "FOUND in field " & x end repeat return "NOT FOUND" end multiWordFind (If you expected the match to be in a card field, repeat also for the number of card fields.) on searchStackFor string set lockScreen to true find string if the result is "Not Found" then cleanExit "This stack doesnÕt contain: " & string --Use the above two lines or use the script --at the end as an alternate to find offset. put the id of this card into startedHere repeat get multiWordFind (string) if word 1 of it is "FOUND" then cleanExit it go next card -- so a subsequent find wonÕt find the same -- card over again find string if the id of this card is startedHere then cleanExit "This stack doesnÕt contain: " & string end repeat end searchStackFor on cleanExit prompt put prompt set lockScreen to false exit to HyperCard end cleanExit --Use the following as an alternate to determine the offset. if word 1 of it is "FOUND" then cleanExit it && "at character position" && offset (string, the value of word 3 to 4 of it) end if ==================== Grouping Buttons by Sioux Lacy Sioux Lacy, one of the outstanding HyperCard testers, has donated this script to provide you, the user, an often-desired script for moving a group of buttons and/or fields around on a card. We are always trying to give you what you ask for, so please let us know if this script is helpful to you. --Editor Many users have asked about grouping objects. This stack presents a method for assigning to a group any number of buttons or fields, and then being able to move that group as a unit, or copying and pasting that group onto another card. This is accomplished with a series of handlers in a card field, called ÒmenuFieldÓ. It looks somewhat like a menu, accepts clicks on any command that it displays, and can be copied and pasted onto another card. The menuField has a Help option that allows the user to read about each of its options. Note that the menuField needs to be a card field in order to work properly. And, when a group has been pasted, it will require re-grouping if its group identity is to work in the new context. Also, since it is difficult to select overlapping objects to be members of a group, it is recommended that they be positioned so they don't overlap. Groupies 1.3 by Sioux Lacy, November 6, 1987. AppleLink comments to me at LACY1, or send mail to Sioux Lacy, MS 27-AQ, 20525 Mariani Ave., Cupertino, CA 95014. --Groupies 1.3 by Sioux Lacy --November 6, 1987 on NewField get editBkgnd if it is true then set editBkgnd to false put "The menuField cannot be a bkgnd field." && "Delete this field & paste again.." exit New Field end if put "Help" & return & "Group" & return & "Move" & return  & "Copy" & return & "Paste" & return & "Clear" & return  into card field id (the id of me) choose browse tool end NewField on mouseUp put the id of me into myID put the mouseV into clickLoc put "HelpMe,NewGroup,MoveGroup,CopyGroup,PasteGroup,ClearGroup"  into messages repeat with x = 1 to the number of lines in card field id myID put "" into char 1 of line x of card field id myID end repeat put the textHeight of me into height put item 2 of the rect of me + height into baseLine repeat with x = 1 to the number of lines in card field id myID if clickLoc < baseLine then put "Ã" into char 1 of line x of card field id myID send item x of messages to me exit mouseUp end if add height to baseLine end repeat end mouseUp on HelpMe ask "Which option would you like help on?" with "Group" if it is empty then exit HelpMe if it is "Group" then put "This option will let you specify objects to be grouped. else if it is "Move" then put "This option will let you move the group." else if it is "Copy" then put "This option used in conjunction with Paste will copy" &&  "& paste the group." else if it is "Paste" then put "This option used in conjunction with Copy will copy" &&  "& paste the group." else if it is "Clear" then put "This option will delete all the objects in the group." else put "Never heard of that option.Ó end HelpMe on NewGroup global objectList put "Shift-click to include objects in group. Option-click when done." put empty into objectList repeat set cursor to 2 wait until the mouseClick put the mouseLoc into thisClick set cursor to 4 if the optionKey is down then exit repeat repeat with x = the number of card buttons down to 1 if isClickWithinObject (thisClick, rect of card btn x) then put "card btn id " & the id of card btn x & "," after objectList exit repeat end if end repeat repeat with x = the number of bkgnd buttons down to 1 if isClickWithinObject (thisClick, rect of bkgnd btn x) then put "bkgnd btn id " & the id of bkgnd btn x & "," after objectList exit repeat end if end repeat repeat with x = the number of card fields down to 1 if isClickWithinObject (thisClick, rect of card field x) then put "card field id " & the id of card field x & "," after objectList exit repeat end if end repeat repeat with x = the number of bkgnd fields down to 1 if isClickWithinObject (thisClick, rect of bkgnd field x) then put "bkgnd field id " & the id of bkgnd field x & "," after objectList exit repeat end if end repeat end repeat put empty into last char of objectList put "The group consists of: " & objectList end NewGroup function isClickWithinObject thisClick, theRect if ((item 1 of theRect) <= (item 1 of thisClick)) and  ((item 2 of theRect) <= (item 2 of thisClick)) and  ((item 3 of theRect) >= (item 1 of thisClick)) and  ((item 4 of theRect) >= (item 2 of thisClick)) then return true else return false end isClickWithinObject on MoveGroup global objectList if objectList is empty then put "There are no objects in the group." exit MoveGroup end if put "Click and drag the group with mouse down. There is an initial delay." wait until the mouseClick put the mouseLoc into myLoc set cursor to 4 put empty into horizontalOffset put empty into verticalOffset repeat with i = 1 to the number of items in objectList put the location of item i of objectList into theLoc put item 1 of theLoc - item 1 of myLoc & "," after horizontalOffset put item 2 of theLoc - item 2 of myLoc & "," after verticalOffset end repeat put empty into last char of horizontalOffset put empty into last char of verticalOffset set cursor to 2 repeat while the mouse is down get the mouseLoc repeat with i = 1 to the number of items in objectList put it into theLoc add item i of horizontalOffset to item 1 of theLoc add item i of verticalOffset to item 2 of theLoc set location of item i of objectList to theLoc end repeat end repeat end MoveGroup on CopyGroup global WhereTheGroupIs set lockScreen to true choose field tool click at the location of me doMenu "Copy Field" choose browse tool put the long id of this card into WhereTheGroupIs put "Go to another card, type cmd-V, & choose Paste from the menuField." set lockScreen to false end CopyGroup on PasteGroup global whereTheGroupIs, objectList if whereTheGroupIs = empty then put "Please choose Copy from the menuField." else if objectList = empty then put "There are no objects in the group." else set cursor to 4 set lockMessages to true set lockScreen to true repeat with i = 1 to the number of items in objectList push this card go to WhereTheGroupIs get item i of objectList if word 2 of it is "btn" then choose button tool else choose field tool if word 1 of it is "bkgnd" then set editBkgnd to true click at the location of it type "C" with commandKey pop card type "V" with commandKey set editBkgnd to false end repeat choose browse tool put "To group these new objects, " &  "choose Group from the menuField." set lockScreen to false end if end PasteGroup on ClearGroup global objectList put "The group consists of: " & objectList answer "Clearing group is not undoable. Are you sure?"  with "Yes" or "Cancel" if it is "Cancel" then exit ClearGroup repeat with i = the number of items in objectList down to 1 get item i of objectList if word 2 of it is "btn" then choose button tool else choose field tool click at the location of it type "X" with commandKey end repeat choose browse tool put empty into objectList end ClearGroup